import queue
import time
from datetime import datetime , timedelta
import paho.mqtt.client as mqtt


class TUtils:
    def __init__(self):
        pass
    @staticmethod
    def tdbQuerySuccess( queryResult):
        res = 0
        try:
            if( 'results' in queryResult.keys() and len(queryResult['results'])>0 ):
                if ('series' in  (queryResult['results'][0]).keys() ):
                    res = len(queryResult['results'][0]['series'])
        except Exception as er:
            print('tdb query success fail')
        return  res
    @staticmethod
    def tdbQuerySeries( queryResult):
        res = []
        try:
            series = queryResult['results'][0]['series']
            for ser in series:
                dictCol = ser['columns']
                item = [dict(zip(dictCol , x)) for x in ser['values']]
                res.append(item)
        except Exception as er:
            print('tdb query success fail')
        return  res

class TUtilsTime:
    def __init__(self):
        pass
    @staticmethod
    def utc2local(utcTime):
        res = ""
        try:
            localTm = datetime.strptime(utcTime, "%Y-%m-%dT%H:%M:%SZ") + timedelta(hours=8)
            res = localTm.strftime("%Y-%m-%d %H:%M:%S")
        except Exception as er:
            print(er)
        return  res
    @staticmethod
    def local2Utc(localTime):
        res = ""
        try:
            localTm = datetime.strptime(localTime, "%Y-%m-%d %H:%M:%S") + timedelta(hours=-8)
            res = localTm.strftime("%Y-%m-%dT%H:%M:%SZ")
        except Exception as er:
            print(er)
        return  res
    @staticmethod
    def time2Utc(dt):
        res = ""
        try:
            res  = (dt + timedelta(hours=-8)).strftime("%Y-%m-%dT%H:%M:%SZ")
        except Exception as er:
            print(er)
        return  res
    @staticmethod
    def time2Local(dt):
        res = ""
        try:
            res  = dt.strftime("%Y-%m-%dT%H:%M:%SZ")
        except Exception as er:
            print(er)
        return  res
    @staticmethod
    def getTimes(timeKey , timeFormat="%Y%m%d%H%M%S"):
        res = {
            "dt":None,
            "strUtc":"",
            "strLocal":""
        }
        try:
            dt = datetime.strptime(timeKey , timeFormat)
            strLocal  = dt.strftime("%Y-%m-%d %H:%M:%S")
            strUtc  = (dt + timedelta(hours=-8)).strftime("%Y-%m-%dT%H:%M:%SZ")
            res = {
                "dt":dt,
                "strUtc":strLocal,
                "strLocal":strUtc
            }
        except Exception as er:
            print(er)
        return  res
class TUtils645:
    def __init__(self):
        self.version="645"
    @classmethod
    def encode645(self , addr , itemCode3210):
        res =None
        try:
            address = ("000000000000"+addr)[-12:]
            addrArr = [ address[x*2:x*2+2] for x in range(6)]
            addrList  =  [ int(x, 16) for x in addrArr ]
            addrList.reverse()

            itemCodeStr = ("00000000"+itemCode3210)[-8:]
            itemCodeList = [ int(itemCodeStr[x*2:x*2+2],16)+0x33 for x in range(4)]
            itemCodeList.reverse()

            msgList =[0x68] + addrList + [0x68 , 0x11 , 0x04] + itemCodeList
            cs =0
            for i in msgList:
                cs = cs + i
                cs = cs % 256
            msgList = msgList +[cs , 0x16]
            res = bytearray(msgList)
            msgList.clear()
            msgList = None
        except Exception as err:
            print(err,"get645Cmd")
        return res
    @classmethod
    def decode645(self , dataBytes):
        res ={
            "status":0 ,
            "addr":"",
            "itemCode":"",
            "valueStr":""
        }
        try:
            dataList = list(dataBytes)
            #dataList =[0xfe,0x68 ,0x94,0x63,0x66,0x72,0x15,0x00,0x68,0x91,0x08,0x33,0x33,0x34,0x33,0x56,0xc9,0x3b,0x33,0xa7,0x16]
            pos68 = bytearray(dataList).find(0x68)
            pos16 = bytearray(dataList).find(0x16)
            flag = pos68>=0 and pos16>0 and dataList[-1]==0x16
            if flag :
                recFlag = True
                if recFlag :
                    dataList = dataList[pos68:]
                    addrList = dataList[1:7]
                    addrList.reverse()
                    itemList = [x-0x33 for x in dataList[10:14]]
                    itemList.reverse()
                    valueList = [x-0x33 for x in dataList[14:-2]]
                    valueList.reverse()
                    def i16tostr( int16):
                        res = hex(int16).replace("0x","00")
                        return res[-2:]
                    res['addr'] = "".join([i16tostr(x) for x in addrList])
                    res['itemCode'] = "".join([i16tostr(x) for x in itemList])
                    res['valueStr'] = "".join([i16tostr(x) for x in valueList])
                    res['status'] = 1
                else:
                    res['status'] = -1020

            else:
                res['status'] = -1011
        except Exception as err:
            print(err,"get645Cmd")
        return res
    @classmethod
    def getValue(self , valueStr  , negativeFlag):
        res = 0
        try:
            v =0
            strValue = valueStr
            flag = 1
            if negativeFlag>0:
                header = int( strValue[0],16)
                if header & 0x8>0:
                    flag = -1
                    strValue=strValue[1:]
            '''
            if decSize>0 :
                strValue = strValue[:-1*decSize] +"."+strValue[-1*decSize:]
            v = float(strValue)
            if r2!=1 :
                v = v * r2
            strValue = str(v)
            pos = strValue.find('.')
            if pos >=0 :
                pos = pos + decSize
                strValue = strValue[:pos+1]
            '''
            res = flag * float(strValue)
        except Exception as err:
            print(err,"get645Cmd")
        return res
    @classmethod
    def convertValue(self , data , decSize , r1 ,r2 ):
        res = 0
        try:
            if decSize==0:
                res = int( data * r1 * r2)
            else:
                valStr = str(data * r1 * r2)
                pos = valStr.find(".")
                if ( pos > 0):
                    if decSize==0:
                        res = float(valStr[:pos])
                    else:
                        res = float(valStr[:pos+decSize+1])
        except Exception as err:
            print(err,"get645Cmd")
        return res
class TMqtt:
    def __init__(self):
        self.settings={
            "host":"",
            "port":0,
            "uid":"",
            "pwd":"" ,
            "subTopics":[],
            "reconnectTime": 5
        }
        self.client=  mqtt.Client()
        self.clientId = ""
        '''
        self.onConnectSuccess= None
        self.onConnectFail = None
        self.onDisConnect = None
        self.onMsg=None
        '''
        self.forceClosed = False
        self.onMsg = None

    def reset(self):
        try:
            self.disconnect()
            self.connect()
        except Exception as er:
            print(er)
    def connect(self):
        res = {
            "status" :0
        }
        try:
            self.disconnect()
            self.forceClosed = False
            clientId = self.clientId if self.clientId!="" else 'mq-'+str(int(1000*time.time()))
            self.clientId = clientId
            host =  self.settings['host']
            port =  self.settings['port']
            uid =  self.settings['uid']
            pwd =  self.settings['pwd']
            #self.client=  mqtt.Client(mqtt.CallbackAPIVersion.VERSION2 , client_id= clientId)
            self.client=  mqtt.Client(client_id= clientId)
            self.client.on_connect = self.client.on_connect
            self.client.on_connect_fail = self.on_connect_fail
            self.client.on_disconnect = self.on_disconnect
            self.client.on_message = self.on_message
            self.client.username_pw_set(uid , pwd )
            code = self.client.connect(host, port, 60)
            if code ==0 :
                for topic in self.settings['subTopics']:
                    self.client.subscribe(topic)
            print(f'connect to mqtt server.{host}:{port}.[{code}]')
            self.client.loop_start()
            res['status']=1
        except Exception as er:
            print(er)
        return res
    def disconnect(self):
        res = {
            "status" :0
        }
        try:
            self.forceClosed = True
            if( self.client!=None):
                if self.client.is_connected():
                    self.disconnect()
                self.client = None
        except Exception as er:
            print(er)
        return res
    def on_connect(self , client, userdata, flags, reason_code, properties):
        try:
            print(f"on mq client connected .code:{flags} , reason:{reason_code}")
            for topic in self.settings['subTopics']:
                self.client.subscribe(topic)
        except Exception as er:
            print(er)
    def on_connect_fail(self , client, userdata):
        try:
            print('---------  connect mqtt server fail!  ---------------')
        except Exception as er:
            print(er)
    def on_disconnect(self , client, userdata, disconnect_flags, reason_code, properties):
        try:
            print('---------  disconnect from mqtt fail!  ---------------')
            print(f'disconnect_flags:{disconnect_flags}, reason_code:{reason_code}, properties:{properties}')
            print('-------------------------------------------------------')
            if not self.forceClosed:
                delay = self.settings['reconnectTime']
                time.sleep(delay)
                self.connect()
        except Exception as er:
            print(er)
    def on_message(self , client, userdata, message):
        try:
            if self.onMsg!=None:
                self.onMsg(message)
        except Exception as er:
            print(er)

